using System;
using System.Threading;
using System.Windows.Forms;
using Fornax020.SerialComm.Core;
using Fornax020.SerialComm.Parsing;
using Fornax020.SerialComm.Protocol;

namespace Fornax020.Devices
{
    /// <summary>
    /// @file XRayGenerator.cs
    /// @brief X射线高压发生器设备管理器
    /// @details 负责X射线设备的所有业务逻辑操作，实现UI与设备操作的完全解耦
    /// 
    /// 设计模式应用：
    /// 1. 单一职责原则：专门负责X射线设备的业务逻辑
    /// 2. 观察者模式：通过事件通知UI层设备状态变化
    /// 3. 命令模式：封装设备操作为命令对象
    /// 4. 策略模式：可扩展的设备控制策略
    /// 5. 依赖注入：通过构造函数注入依赖
    /// 
    /// @author Fornax020 Development Team
    /// @date 2024
    /// @version 2.0.0
    /// </summary>
    public class XRayGenerator : IDisposable
    {
        #region 私有字段
        private readonly SerialManager _serialManager;
        private readonly ResponseParser _dataParser;
        private readonly XRayDeviceConfig _config;
        private readonly XRayDeviceState _state;
        private System.Timers.Timer _monitoringTimer;
        private bool _isDisposed = false;
        private volatile bool _isDisposing = false;
        #endregion

        #region 事件定义 - 观察者模式
        /// <summary>
        /// 设备状态变化事件
        /// </summary>
        public event EventHandler<DeviceStatusEventArgs> StatusChanged;
        
        /// <summary>
        /// 连接状态变化事件
        /// </summary>
        public event EventHandler<ConnectionStatusEventArgs> ConnectionStatusChanged;
        
        /// <summary>
        /// 错误发生事件
        /// </summary>
        public event EventHandler<ErrorEventArgs> ErrorOccurred;
        
        /// <summary>
        /// 曝光状态变化事件
        /// </summary>
        public event EventHandler<ExposureStatusEventArgs> ExposureStatusChanged;
        #endregion

        #region 公共属性 - 委托给状态类
        /// <summary>
        /// 当前KV值
        /// </summary>
        public double CurrentKv 
        { 
            get => _state.CurrentKv; 
            private set => _state.CurrentKv = value; 
        }

        /// <summary>
        /// 当前MA值
        /// </summary>
        public double CurrentMa 
        { 
            get => _state.CurrentMa; 
            private set => _state.CurrentMa = value; 
        }

        /// <summary>
        /// 设备反馈的KV值
        /// </summary>
        public double FeedbackKv => _state.FeedbackKv;

        /// <summary>
        /// 设备反馈的MA值
        /// </summary>
        public double FeedbackMa => _state.FeedbackMa;

        /// <summary>
        /// 设备反馈的FIL值
        /// </summary>
        public double FeedbackFil => _state.FeedbackFil;

        /// <summary>
        /// 固件版本
        /// </summary>
        public string FirmwareVersion => _state.FirmwareVersion;

        /// <summary>
        /// 最后的错误信息
        /// </summary>
        public string LastError => _state.LastError;

        /// <summary>
        /// 是否已连接
        /// </summary>
        public bool IsConnected => _state.IsConnected;

        /// <summary>
        /// 是否正在曝光
        /// </summary>
        public bool IsExposing => _state.IsExposing;

        /// <summary>
        /// 设备状态
        /// </summary>
        public XRayDeviceState State => _state;

        /// <summary>
        /// 设备配置
        /// </summary>
        public XRayDeviceConfig Config => _config;
        #endregion

        #region 构造函数
        /// <summary>
        /// @brief 默认构造函数
        /// @details 使用默认配置创建X射线设备管理器
        /// </summary>
        public XRayGenerator() : this(
            new SerialManager(),
            new ResponseParser(),
            XRayDeviceConfig.Default)
        {
        }

        /// <summary>
        /// @brief 带配置的构造函数
        /// @details 使用指定配置创建X射线设备管理器
        /// @param config 设备配置
        /// </summary>
        public XRayGenerator(XRayDeviceConfig config) : this(
            new SerialManager(),
            new ResponseParser(),
            config)
        {
        }

        /// <summary>
        /// @brief 完整构造函数 - 依赖注入
        /// @details 通过构造函数注入所有依赖
        /// @param serialManager 串口管理器
        /// @param dataParser 数据解析器
        /// @param config 设备配置
        /// </summary>
        public XRayGenerator(
            SerialManager serialManager,
            ResponseParser dataParser,
            XRayDeviceConfig config)
        {
            _serialManager = serialManager ?? throw new ArgumentNullException(nameof(serialManager));
            _dataParser = dataParser ?? throw new ArgumentNullException(nameof(dataParser));
            _config = config ?? throw new ArgumentNullException(nameof(config));
            _state = new XRayDeviceState();
            
            // 订阅串口管理器事件
            _serialManager.DataReceived += OnDataReceived;
            _serialManager.ConnectionStatusChanged += OnConnectionStatusChanged;
            _serialManager.ErrorOccurred += OnErrorOccurred;
            
            // 订阅状态变化事件
            _state.PropertyChanged += OnStatePropertyChanged;
            
            // 初始化监控定时器
            InitializeMonitoringTimer();
        }
        #endregion

        #region 公共方法
        /// <summary>
        /// @brief 连接设备
        /// @details 连接到X射线设备
        /// @param portName 串口名称
        /// @param baudRate 波特率
        /// @return 连接是否成功
        /// </summary>
        public bool Connect(string portName, int baudRate)
        {
            try
            {
                // 如果已经连接，先断开
                if (IsConnected)
                {
                    Disconnect();
                    Thread.Sleep(_config.ReconnectInterval);
                }

                bool result = _serialManager.Connect(portName, baudRate);
                if (result)
                {
                    _state.IsConnected = true;
                    StartMonitoring(); // 启用定时器发送MO指令
                    LogMessage($"设备连接成功: {portName}, 波特率: {baudRate}");
                }
                return result;
            }
            catch (Exception ex)
            {
                _state.LastError = $"连接设备失败: {ex.Message}";
                return false;
            }
        }
        
        /// <summary>
        /// @brief 断开设备连接
        /// @details 断开与X射线设备的连接
        /// @return 断开是否成功
        /// </summary>
        public bool Disconnect()
        {
            try
            {
                StopMonitoring();
                _serialManager.Disconnect();
                _state.IsConnected = false;
                _state.IsExposing = false;
                LogMessage("设备连接已断开");
                return true;
            }
            catch (Exception ex)
            {
                _state.LastError = $"断开连接失败: {ex.Message}";
                return false;
            }
        }

        /// <summary>
        /// @brief 设置KV值
        /// @details 设置X射线管的电压值
        /// @param kvValue KV值
        /// @return 设置是否成功
        /// </summary>
        public bool SetKv(double kvValue)
        {
            try
            {
                // 使用配置验证参数
                if (!_config.IsValidKvValue(kvValue))
                {
                    _state.LastError = _config.GetKvValueError(kvValue);
                    return false;
                }

                if (!IsConnected)
                {
                    _state.LastError = "设备未连接";
                    return false;
                }
                
                // 使用命令模式发送KV设置命令
                var command = CommandFactory.CreateSetKvCommand(kvValue);
                bool result = command.Execute(_serialManager);
                
                if (result)
                {
                    CurrentKv = kvValue;
                    LogMessage($"KV设置命令发送成功: {kvValue}");
                }
                else
                {
                    _state.LastError = "KV设置命令发送失败";
                }
                
                return result;
            }
            catch (Exception ex)
            {
                _state.LastError = $"设置KV值异常: {ex.Message}";
                return false;
            }
        }

        /// <summary>
        /// @brief 设置MA值
        /// @details 设置X射线管的电流值
        /// @param maValue MA值
        /// @return 设置是否成功
        /// </summary>
        public bool SetMa(double maValue)
        {
            try
            {
                // 使用配置验证参数
                if (!_config.IsValidMaValue(maValue))
                {
                    _state.LastError = _config.GetMaValueError(maValue);
                    return false;
                }

                if (!IsConnected)
                {
                    _state.LastError = "设备未连接";
                    return false;
                }
                
                // 使用命令模式发送MA设置命令
                var command = CommandFactory.CreateSetMaCommand(maValue);
                bool result = command.Execute(_serialManager);
                
                if (result)
                {
                    CurrentMa = maValue;
                    LogMessage($"MA设置命令发送成功: {maValue}");
                }
                else
                {
                    _state.LastError = "MA设置命令发送失败";
                }
                
                return result;
            }
            catch (Exception ex)
            {
                _state.LastError = $"设置MA值异常: {ex.Message}";
                return false;
            }
        }

        /// <summary>
        /// @brief 开始曝光
        /// @details 启动X射线曝光
        /// @return 开始曝光是否成功
        /// </summary>
        public bool StartExposure()
        {
            try
            {
                if (!IsConnected)
                {
                    _state.LastError = "设备未连接";
                    return false;
                }
                
                // 使用命令模式发送开始曝光命令
                var command = CommandFactory.CreateStartExposureCommand();
                bool result = command.Execute(_serialManager);
                
                if (result)
                {
                    _state.IsExposing = true;
                    LogMessage("开始曝光命令发送成功");
                }
                else
                {
                    _state.LastError = "开始曝光命令发送失败";
                }
                
                return result;
            }
            catch (Exception ex)
            {
                _state.LastError = $"开始曝光异常: {ex.Message}";
                return false;
            }
        }

        /// <summary>
        /// @brief 停止曝光
        /// @details 停止X射线曝光
        /// @return 停止曝光是否成功
        /// </summary>
        public bool StopExposure()
        {
            try
            {
                if (!IsConnected)
                {
                    LogMessage("设备未连接，曝光状态已重置");
                    _state.IsExposing = false;
                    return true;
                }
                
                // 使用命令模式发送停止曝光命令
                var command = CommandFactory.CreateStopExposureCommand();
                bool result = command.Execute(_serialManager);
                
                if (result)
                {
                    _state.IsExposing = false;
                    LogMessage("停止曝光命令发送成功");
                }
                else
                {
                    _state.LastError = "停止曝光命令发送失败";
                }
                
                return result;
            }
            catch (Exception ex)
            {
                _state.LastError = $"停止曝光异常: {ex.Message}";
                return false;
            }
        }

        /// <summary>
        /// @brief 清除错误
        /// @details 清除设备错误状态
        /// @return 清除错误是否成功
        /// </summary>
        public bool ClearError()
        {
            try
            {
                if (!IsConnected)
                {
                    _state.LastError = "设备未连接";
                    return false;
                }
                
                // 使用命令模式发送清除错误命令
                var command = CommandFactory.CreateClearErrorCommand();
                bool result = command.Execute(_serialManager);
                
                if (result)
                {
                    _state.ClearError();
                    LogMessage("清除错误命令发送成功");
                }
                else
                {
                    _state.LastError = "清除错误命令发送失败";
                }
                
                return result;
            }
            catch (Exception ex)
            {
                _state.LastError = $"清除错误异常: {ex.Message}";
                return false;
            }
        }

        /// <summary>
        /// @brief 强制断开连接
        /// @details 强制断开设备连接，用于异常情况
        /// </summary>
        public void ForceDisconnect()
        {
            try
            {
                LogMessage("开始强制断开连接");
                
                // 1. 停止监控
                StopMonitoring();
                
                // 2. 停止曝光
                if (IsExposing)
                {
                    StopExposure();
                }
                
                // 3. 强制断开串口连接
                try
                {
                    _serialManager.Disconnect();
                    _state.IsConnected = false;
                    LogMessage("串口连接已强制断开");
                }
                catch (Exception ex)
                {
                    LogMessage($"强制断开串口连接时发生异常: {ex.Message}");
                }
                
                LogMessage("强制断开连接完成");
            }
            catch (Exception ex)
            {
                LogMessage($"强制断开连接时发生异常: {ex.Message}");
            }
        }
        #endregion

        #region 私有方法
        /// <summary>
        /// @brief 初始化监控定时器
        /// @details 根据配置初始化监控定时器
        /// </summary>
        private void InitializeMonitoringTimer()
        {
            _monitoringTimer = new System.Timers.Timer(_config.MonitoringInterval);
            _monitoringTimer.AutoReset = true;
            _monitoringTimer.Elapsed += OnMonitoringTimerTick;
        }

        /// <summary>
        /// @brief 开始监控
        /// @details 启动设备状态监控
        /// </summary>
        private void StartMonitoring()
        {
            if (_monitoringTimer != null && !_monitoringTimer.Enabled)
            {
                _monitoringTimer.Start();
                LogMessage($"监控已启动，间隔: {_config.MonitoringInterval}ms");
            }
        }

        /// <summary>
        /// @brief 停止监控
        /// @details 停止设备状态监控
        /// </summary>
        private void StopMonitoring()
        {
            if (_monitoringTimer != null && _monitoringTimer.Enabled)
            {
                _monitoringTimer.Stop();
                LogMessage("监控已停止");
            }
        }

        /// <summary>
        /// @brief 监控定时器事件处理
        /// @details 定期查询设备状态
        /// @param sender 事件发送者
        /// @param e 定时器事件参数
        /// </summary>
        private void OnMonitoringTimerTick(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                if (_isDisposing || !IsConnected)
                {
                    return;
                }

                LogMessage("监控定时器触发，发送MO指令查询设备状态");
                
                // 发送监控查询命令（MO指令）
                var monitorCommand = CommandFactory.CreateMonitorQueryCommand();
                bool monitorResult = monitorCommand.Execute(_serialManager);
                LogMessage($"MO指令发送结果: {monitorResult}");
                
                // 暂时不发送GR指令，只发送MO指令
                // var versionCommand = CommandFactory.CreateVersionQueryCommand();
                // bool versionResult = versionCommand.Execute(_serialManager);
                // LogMessage($"GR指令发送结果: {versionResult}");
            }
            catch (Exception ex)
            {
                LogMessage($"监控定时器异常: {ex.Message}");
            }
        }

        /// <summary>
        /// @brief 数据接收事件处理
        /// @details 处理从设备接收到的数据
        /// @param sender 事件发送者
        /// @param e 数据接收事件参数
        /// </summary>
        private void OnDataReceived(object sender, DataReceivedEventArgs e)
        {
            try
            {
                // 如果正在释放资源，直接返回，不处理数据
                if (_isDisposing)
                {
                    LogMessage("正在释放资源，跳过数据接收处理");
                    return;
                }
                
                // 添加调试日志
                LogMessage($"接收到数据: '{e.DataString}'");
                LogMessage($"原始字节数据: {BitConverter.ToString(e.RawData)}");
                LogMessage($"数据长度: {e.DataString.Length}");
                
                // 使用策略模式解析数据
                var parsedData = _dataParser.Parse(e.DataString);
                
                LogMessage($"解析结果: CommandType='{parsedData.CommandType}', KvValue={parsedData.KvValue}, IsValid={parsedData.IsValid}");
                
                if (parsedData.IsValid)
                {
                    ProcessResponseData(parsedData);
                }
                else
                {
                    LogMessage($"数据解析无效: '{e.DataString}'");
                }
            }
            catch (Exception ex)
            {
                // 如果正在释放资源，不更新错误状态
                if (!_isDisposing)
                {
                    _state.LastError = $"数据处理异常: {ex.Message}";
                }
                LogMessage($"数据处理异常: {ex.Message}");
            }
        }
        
        /// <summary>
        /// @brief 处理解析后的数据
        /// @details 根据命令类型更新设备状态
        /// @param parsedData 解析后的数据
        /// </summary>
        private void ProcessResponseData(ResponseData parsedData)
        {
            LogMessage($"处理解析数据: CommandType={parsedData.CommandType}");
            
            switch (parsedData.CommandType)
            {
                case ProtocolConstants.CommandTypes.KV_FEEDBACK:
                    _state.FeedbackKv = parsedData.KvValue;
                    _state.LastCommandType = parsedData.CommandType;
                    LogMessage($"VP指令处理: FeedbackKv设置为{_state.FeedbackKv}");
                    OnStatusChanged(parsedData.CommandType);
                    break;
                    
                case ProtocolConstants.CommandTypes.MA_FEEDBACK:
                    _state.FeedbackMa = parsedData.MaValue;
                    _state.LastCommandType = parsedData.CommandType;
                    LogMessage($"CP指令处理: FeedbackMa设置为{_state.FeedbackMa}");
                    OnStatusChanged(parsedData.CommandType);
                    break;
                    
                case ProtocolConstants.CommandTypes.FIL_FEEDBACK:
                    _state.FeedbackFil = parsedData.FilValue;
                    _state.LastCommandType = parsedData.CommandType;
                    LogMessage($"FI指令处理: FeedbackFil设置为{_state.FeedbackFil}");
                    OnStatusChanged(parsedData.CommandType);
                    break;
                    
                case ProtocolConstants.CommandTypes.MONITOR_DATA:
                    // MO指令包含KV、MA、FIL三个值
                    _state.FeedbackKv = parsedData.KvValue;
                    _state.FeedbackMa = parsedData.MaValue;
                    _state.FeedbackFil = parsedData.FilValue;
                    _state.LastCommandType = parsedData.CommandType;
                    LogMessage($"MO指令处理: FeedbackKv={_state.FeedbackKv}, FeedbackMa={_state.FeedbackMa}, FeedbackFil={_state.FeedbackFil}");
                    LogMessage($"MO指令处理: CommandType={parsedData.CommandType}, LastCommandType={_state.LastCommandType}");
                    OnStatusChanged(parsedData.CommandType);
                    LogMessage($"MO指令处理: OnStatusChanged已调用，CommandType={parsedData.CommandType}");
                    break;
                    
                case ProtocolConstants.CommandTypes.FIRMWARE_VERSION:
                    _state.FirmwareVersion = parsedData.FirmwareVersion;
                    _state.LastCommandType = parsedData.CommandType;
                    LogMessage($"GR指令处理: FirmwareVersion设置为{_state.FirmwareVersion}");
                    OnStatusChanged(parsedData.CommandType);
                    break;
                    
                case ProtocolConstants.CommandTypes.ERROR_INFO:
                    _state.LastError = parsedData.ErrorCode;
                    _state.LastCommandType = parsedData.CommandType;
                    LogMessage($"ER指令处理: LastError设置为{_state.LastError}");
                    OnStatusChanged(parsedData.CommandType);
                    // 接收到错误时自动停止曝光
                    if (IsExposing)
                    {
                        StopExposure();
                    }
                    break;
                    
                case ProtocolConstants.CommandTypes.START_EXPOSURE_RESPONSE:
                    _state.IsExposing = true;
                    _state.LastCommandType = parsedData.CommandType;
                    LogMessage($"EN1指令处理: 曝光状态设置为true");
                    OnStatusChanged(parsedData.CommandType);
                    break;
                    
                case ProtocolConstants.CommandTypes.STOP_EXPOSURE_RESPONSE:
                    _state.IsExposing = false;
                    _state.LastCommandType = parsedData.CommandType;
                    LogMessage($"EN0指令处理: 曝光状态设置为false");
                    OnStatusChanged(parsedData.CommandType);
                    break;
                    
                case ProtocolConstants.CommandTypes.CLEAR_ERROR_RESPONSE:
                    _state.LastError = null; // 清除错误状态
                    _state.LastCommandType = parsedData.CommandType;
                    LogMessage($"CL指令处理: 错误状态已清除");
                    OnStatusChanged(parsedData.CommandType);
                    break;
                    
                default:
                    LogMessage($"未知命令类型: {parsedData.CommandType}");
                    break;
            }
            
            // 更新状态时间戳
            _state.UpdateTimestamp();
        }
        
        /// <summary>
        /// @brief 连接状态变化事件处理
        /// @details 处理串口连接状态变化
        /// @param sender 事件发送者
        /// @param e 连接状态事件参数
        /// </summary>
        private void OnConnectionStatusChanged(object sender, ConnectionStatusEventArgs e)
        {
            _state.IsConnected = e.IsConnected;
        }
        
        /// <summary>
        /// @brief 错误事件处理
        /// @details 处理串口通信错误
        /// @param sender 事件发送者
        /// @param e 错误事件参数
        /// </summary>
        private void OnErrorOccurred(object sender, ErrorEventArgs e)
        {
            _state.LastError = e.ErrorMessage;
        }

        /// <summary>
        /// @brief 状态属性变化事件处理
        /// @details 当设备状态发生变化时触发相应事件
        /// @param sender 事件发送者
        /// @param e 属性变化事件参数
        /// </summary>
        private void OnStatePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            // 根据不同的属性变化触发不同的事件
            switch (e.PropertyName)
            {
                case nameof(XRayDeviceState.IsConnected):
                    OnConnectionStatusChanged(_state.IsConnected);
                    break;
                case nameof(XRayDeviceState.IsExposing):
                    OnExposureStatusChanged(_state.IsExposing);
                    break;
                case nameof(XRayDeviceState.LastError):
                    if (!string.IsNullOrEmpty(_state.LastError))
                    {
                        OnErrorOccurred(_state.LastError);
                    }
                    break;
            }
        }
        
        /// <summary>
        /// @brief 记录日志消息
        /// @details 输出调试日志信息
        /// @param message 日志消息
        /// </summary>
        private void LogMessage(string message)
        {
            System.Diagnostics.Debug.WriteLine($"[XRayGenerator] {DateTime.Now:HH:mm:ss.fff} - {message}");
        }
        #endregion

        #region 事件触发方法 - 观察者模式
        /// <summary>
        /// @brief 触发设备状态变化事件
        /// @param commandType 命令类型（可选）
        /// </summary>
        protected virtual void OnStatusChanged(string commandType = null)
        {
            LogMessage($"OnStatusChanged被调用: CommandType={commandType}");
            var args = new DeviceStatusEventArgs
            {
                CurrentKv = CurrentKv,
                CurrentMa = CurrentMa,
                FeedbackKv = FeedbackKv,
                FeedbackMa = FeedbackMa,
                FeedbackFil = FeedbackFil,
                FirmwareVersion = FirmwareVersion,
                LastError = LastError,
                CommandType = commandType
            };
            LogMessage($"OnStatusChanged: 创建事件参数 - CommandType={args.CommandType}, FeedbackKv={args.FeedbackKv}, FeedbackMa={args.FeedbackMa}");
            StatusChanged?.Invoke(this, args);
            LogMessage($"OnStatusChanged: 事件已触发");
        }
        
        /// <summary>
        /// @brief 触发连接状态变化事件
        /// @param isConnected 是否已连接
        /// </summary>
        protected virtual void OnConnectionStatusChanged(bool isConnected)
        {
            ConnectionStatusChanged?.Invoke(this, new ConnectionStatusEventArgs(isConnected));
        }
        
        /// <summary>
        /// @brief 触发错误事件
        /// @param errorMessage 错误消息
        /// </summary>
        protected virtual void OnErrorOccurred(string errorMessage)
        {
            ErrorOccurred?.Invoke(this, new ErrorEventArgs(errorMessage));
        }

        /// <summary>
        /// @brief 触发曝光状态变化事件
        /// @param isExposing 是否正在曝光
        /// </summary>
        protected virtual void OnExposureStatusChanged(bool isExposing)
        {
            ExposureStatusChanged?.Invoke(this, new ExposureStatusEventArgs(isExposing));
        }
        #endregion

        #region IDisposable实现
        /// <summary>
        /// @brief 释放资源
        /// @details 释放所有占用的资源
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// @brief 释放资源的具体实现
        /// @param disposing 是否正在释放
        /// </summary>
        protected virtual void Dispose(bool disposing)
        {
            if (!_isDisposed)
            {
                if (disposing)
                {
                    _isDisposing = true;
                    
                    try
                    {
                        // 停止监控
                        StopMonitoring();
                        
                        // 停止曝光
                        if (IsExposing)
                        {
                            StopExposure();
                        }
                        
                        // 断开连接
                        Disconnect();
                        
                        // 释放定时器
                        _monitoringTimer?.Dispose();
                        
                        // 取消事件订阅
                        if (_serialManager != null)
                        {
                            _serialManager.DataReceived -= OnDataReceived;
                            _serialManager.ConnectionStatusChanged -= OnConnectionStatusChanged;
                            _serialManager.ErrorOccurred -= OnErrorOccurred;
                        }
                        
                        if (_state != null)
                        {
                            _state.PropertyChanged -= OnStatePropertyChanged;
                        }
                        
                        LogMessage("XRayGenerator资源已释放");
                    }
                    catch (Exception ex)
                    {
                        LogMessage($"释放资源时发生异常: {ex.Message}");
                    }
                    finally
                    {
                        _isDisposed = true;
                        _isDisposing = false;
                    }
                }
            }
        }
        #endregion
    }
}
